#include <iostream>
#include <string>
#include <functional>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>

#include <cstdlib>
#include <cerrno>
#include <cstring>

//#define MYTHREAD //切换为自己实现的线程库

#include "log.hpp" //logMessage
#include "err.hpp"
#include "Task.hpp"
#include "ThreadPool.hpp"


namespace my_tpcs
{
    struct TaskFunc { void operator()(Task& t) { t(); } }; //V4-线程池 业务处理函数
    
    // class Server;
    // class ThreadData // v3线程创建 线程函数数据
    // {
    // public:
    //     ThreadData(std::string ip, uint16_t port, int sockfd, Server *ser)
    //         : _ip(ip), _port(port), _sockfd(sockfd), _ser(ser)
    //     {
    //     }

    //     std::string _ip;
    //     uint16_t _port;
    //     int _sockfd;
    //     Server *_ser;
    // };

    static const uint16_t defaultport = 8088; // 默认端口号
    static const int backlog = 32;            // 默认sockfd挂起队列长度

    class Server
    {
        typedef std::function<std::string(const std::string &)> FUNC; // 数据处理函数
    public:
        Server(FUNC func, int port = defaultport)
            : _sock(-1), _port(port), _func(func)
        {
        }

        void InitServer()
        {
            // 1.获取sockfd
            _sock = socket(AF_INET, SOCK_STREAM, 0); // 以流式传输 - TCP
            if (_sock == -1)
            {
                logMessage(Fatal, "Server: socket error! code:%d,string error:%s", errno, strerror(errno));
                exit(SOCK_ERR);
            }
            logMessage(Info, "Server: create socket success! code:%d,string error:%s", errno, strerror(errno));

            // 2.绑定bind
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local)); // 初始化local为0
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY;

            if (bind(_sock, (struct sockaddr *)(&local), sizeof(local)) < 0)
            {
                logMessage(Fatal, "Server: bind error! code:%d,string error:%s", errno, strerror(errno));
                exit(BIND_ERR);
            }
            logMessage(Info, "Server: bind success! code:%d,string error:%s", errno, strerror(errno));

            // 3.设置为监听模式
            if (listen(_sock, backlog) < 0) // 第二个参数_n代表的是sockfd挂起的队列长度 不宜过大
            {
                logMessage(Fatal, "Server: listen error! code:%d,string error:%s", errno, strerror(errno));
                exit(BIND_ERR);
            }
            logMessage(Info, "Server: listen success! code:%d,string error:%s", errno, strerror(errno));
        }

        // v1 单连接版
        // v2 多进程版
        // v3 多线程版
        // v4 线程池版
        // void Start() // 开始连接和接收
        // {

        //     //v2 多进程版
        //     //在进行处理前，我们需要父进程忽略子进程的回收信号 让操作系统回收
        //     signal(SIGCHLD,SIG_IGN); //或者自己制定回收方案

        //     while (true)
        //     {
        //         // 4.获取新连接 - 连接一个主机之后开始服务 主机退出就等待写一个主机连接
        //         struct sockaddr_in client;
        //         memset(&client, 0, sizeof(client));
        //         socklen_t len = sizeof(client);
        //         int client_sock = accept(_sock, (struct sockaddr *)(&client), &len); // 开始监听 服务器sockfd 获得的连接 连接成功返回对端的sockfd
        //         if (client_sock < 0)
        //         {
        //             logMessage(Warning, "Server: accept error! code:%d,string error:%s", errno, strerror(errno));
        //             continue;
        //         }

        //         std::string client_ip = inet_ntoa(client.sin_addr); // 获取对端IP
        //         uint16_t client_port = ntohs(client.sin_port);

        //         logMessage(Info, "Server: 获取新连接成功: %d form %d,counterpart ip: %s and port: %d", client_sock, _sock, client_ip.c_str(), client_port);
        //         std::cout<<"获取新连接成功! Client IP:"<<client_ip<<",Client Port:"<<client_port<<std::endl;

        //         // 处理业务并返回 v1
        //         //service(client_sock); //v1一旦链接就开始处理任务

        //     //     pid_t id = fork(); //v2
        //     //     if(id < 0) //子进程创建失败
        //     //     {
        //     //         close(client_sock); //关闭当前client的sockfd
        //     //         continue; //继续工作
        //     //     }
        //     //     else if(id == 0)
        //     //     {
        //     //         close(_sock); //子进程关闭不需要的sockfd 关闭服务器的sockfd
        //     //         if(fork() > 0) exit(0); //孙进程创建成功 子进程退出 孙进程由系统接管执行后面的代码

        //     //         service(client_sock);
        //     //         exit(0);
        //     //     }
        //     //     close(client_sock);//父进程关闭不需要的client_sock fd 防止fd资源泄漏
        //     // }
        // }

        // v3 来一个业务就开一个线程
        void Start() // 开始连接和接收
        {
            while (true) // 监听，来新链接就创建任务
            {
                // 4.获取新连接 - 连接一个主机之后开始服务 主机退出就等待写一个主机连接
                struct sockaddr_in client;
                memset(&client, 0, sizeof(client));
                socklen_t len = sizeof(client);
                int client_sock = accept(_sock, (struct sockaddr *)(&client), &len); // 开始监听 服务器sockfd 获得的连接 连接成功返回对端的sockfd
                if (client_sock < 0)
                {
                    logMessage(Warning, "Server: accept error! code:%d,string error:%s", errno, strerror(errno));
                    continue;
                }

                std::string client_ip = inet_ntoa(client.sin_addr); // 获取对端IP
                uint16_t client_port = ntohs(client.sin_port);

                logMessage(Info, "Server: 获取新连接成功: %d form %d,counterpart ip: %s and port: %d", client_sock, _sock, client_ip.c_str(), client_port);
                std::cout << "获取新连接成功! Client IP:" << client_ip << ",Client Port:" << client_port << std::endl;

                // v3-派发任务 来一个链接就创建一个线程进行服务，保持链接
                //  pthread_t tid;
                //  ThreadData *td = new ThreadData(client_ip, client_port, client_sock, (void*)this);
                //  pthread_create(&tid, nullptr, ThreadFunc, td);

                // v4-线程池，每次请求都需要连接，连接一次，服务一次，放入线程池中
                Task t(client_ip,client_port,client_sock,std::bind(&Server::service,this,std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                ThreadPool<Task,TaskFunc>::GetCreate()->push_task(t);
            }
        }

        // v3-线程 执行函数
        //  static void *ThreadFunc(void *args)
        //  {
        //      pthread_detach(pthread_self()); // 线程分离
        //      ThreadData *td = static_cast<ThreadData*>(args);
        //      td->_ser->service(td->_sockfd);
        //      delete td;
        //      return nullptr;
        //  }

        // v1 v2 v3
        //  void service(int client_sockfd) // v1 单连接处理任务/多进程
        //  {
        //      while(true) //v1 v2 v3(v3保持链接)
        //      {
        //          char readbuf[2048] = {0};
        //          ssize_t n = read(client_sockfd,readbuf,sizeof(readbuf)-1); // 从socked接收缓冲区中流式读取
        //          if(n > 0) //读取到了字符
        //          {
        //              readbuf[n] = '\0';
        //              std::string ret = _func(readbuf); //交给任务处理函数处理
        //              std::cout<<ret<<std::endl; //输出接收并处理的内容

        //             write(client_sockfd,ret.c_str(),ret.size()); //发送回去
        //         }
        //         else if(n == 0) //连接(失败)断开
        //         {
        //             //对方退出连接
        //             std::cout<<"client quit!"<<std::endl;
        //             break;
        //         }
        //         else //其他意外记录日志并退出
        //         {
        //             logMessage(Error,"Server: read error! code:%d,string error:%s", errno, strerror(errno));
        //             break;
        //         }
        //     }
        //     close(client_sockfd); //关闭文件描述符
        // }

        void service(const std::string& client_ip,const uint16_t& client_port,const int& client_sockfd) // v1 单连接处理任务/多进程
        {
            while(true)
            {
                char readbuf[2048] = {0};
                ssize_t n = read(client_sockfd, readbuf, sizeof(readbuf) - 1); // 从socked接收缓冲区中流式读取
                if (n > 0)                                                     // 读取到了字符
                {
                    readbuf[n] = '\0';
                    std::string ret = _func(readbuf); // 交给任务处理函数处理
                    //std::cout << ret << std::endl;    // 输出接收并处理的内容

                    write(client_sockfd, ret.c_str(), ret.size()); // 发送回去
                }
                else if (n == 0) // 连接(失败)断开
                {
                    // 对方退出连接
                    //std::cout << "[IP: "<<client_ip<<"|port: "<<client_port<<"]:client quit!" << std::endl;
                    logMessage(Info, "[IP: %s |port:%d]:client quit!", client_ip.c_str(),client_port);
                    break;
                }
                else // 其他意外记录日志并退出
                {
                    logMessage(Error, "Server: read error! code:%d,string error:%s", errno, strerror(errno));
                    break;
                }
            }

            close(client_sockfd); // 关闭文件描述符
        }

    private:
        int _sock;      // listen sock 监听套接字文件描述符
        uint16_t _port; // 端口
        FUNC _func;     // 任务处理函数
    };
}